#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "driver/gpio.h"

// 宏定义GPIO输入的引脚号
#define GPIO_INPUT_BOOT     9
#define GPIO_INPUT_EXTER    8
#define GPIO_INPUT_PIN_SEL  ((1ULL<<GPIO_INPUT_BOOT) | (1ULL<<GPIO_INPUT_EXTER))
#define ESP_INTR_FLAG_DEFAULT 0

// 全局常量, 字符串, 用于日志打印的标签
const static char* TAG = "button";
// 全局变量, 消息队列, 用户中断到任务的数据传输
static QueueHandle_t gpio_evt_queue = NULL;

// 中断回调函数
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    // 往队列中写入产生中断的gpio引脚号
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

// gpio初始化
void gpio_init(void)
{
    gpio_config_t io_conf = {};
    //设置IO引脚：宏定义中修改
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //设置IO方向：输入
    io_conf.mode = GPIO_MODE_INPUT;
    //设置IO上拉：使能
    io_conf.pull_up_en = 1;
    //设置IO中断类型：上升沿中断和下降沿
    io_conf.intr_type = GPIO_INTR_ANYEDGE;
    //配置GPIO
    gpio_config(&io_conf);

    //安装GPIO中断服务
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //添加GPIO_INPUT_BOOT 中断回调函数
    gpio_isr_handler_add(GPIO_INPUT_BOOT, gpio_isr_handler, (void*) GPIO_INPUT_BOOT);
    //添加GPIO_INPUT_EXTER 中断回调函数
    gpio_isr_handler_add(GPIO_INPUT_EXTER, gpio_isr_handler, (void*) GPIO_INPUT_EXTER);
}

void app_main(void)
{
    uint32_t io_num;

    //GPIO初始化
    gpio_init();

    //创建1个队列，队列长度为10，队列项为uint32_t
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));

    while(true) {
        // 堵塞读取队列中的数据
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            // 读取成功，则打印出gpio引脚号和当前的电平
            ESP_LOGI(TAG, "GPIO[%ld] intr, val: %d", io_num, gpio_get_level(io_num));
        }
    }
}